module scene.gameplay;

import std.datetime, std.string, std.math;

import scene.scene, actor.actor, magic, gameinter;
import mirdefine, mirshare, mirgame, mirmap, mirsound;
import common.lightfog, common.gameutil, common.item, common.particle, common.weathereffect;
import common.systemmsg, common.hintmsg, common.imagearray, common.imagehandler;

import share.container, share.types, share.protocol;

import allegro5.allegro;
import allegro5.allegro_primitives;
import allegro5.allegro_shader;





ALLEGRO_SHADER* create_shader()
{
    auto shader = al_create_shader(ALLEGRO_SHADER_PLATFORM.ALLEGRO_SHADER_GLSL);
    if (shader is null)
        return null;

    auto source = al_get_default_shader_source(ALLEGRO_SHADER_PLATFORM.ALLEGRO_SHADER_AUTO, ALLEGRO_SHADER_TYPE.ALLEGRO_PIXEL_SHADER);

    if (!al_attach_shader_source(shader, ALLEGRO_SHADER_TYPE.ALLEGRO_PIXEL_SHADER, source))
    {
        std.stdio.writeln(al_get_shader_log(shader));
        return null;
    }
    if (!al_attach_shader_source_file(shader, ALLEGRO_SHADER_TYPE.ALLEGRO_PIXEL_SHADER, "go_grey.glsl"))
    {
        std.stdio.writeln(al_get_shader_log(shader));
        return null;
    }
    if (!al_build_shader(shader))
    {
        std.stdio.writeln(al_get_shader_log(shader));
        return null;
    }

    return shader;
}









struct MemMappedId
{
    public Actor pxActor[_MAX_CELL_OBJ];
    public Magic pxMagic[_MAX_CELL_OBJ];
    public PGroundItem pstItem[_MAX_CELL_OBJ];
}

private alias Queue!PPacketMsg PacketQueue;

public class GamePlayScene : Scene
{
    public bool m_bStatusView;
    public bool m_bTileView;
    public bool m_bCellView;
    public bool m_bObj1View;
    public bool m_bObj2View;
    public bool m_bStopPtView;
    public bool m_bShowSnow;
    public bool m_bShowMist;
    public bool m_bShowRain;
    public bool m_bShadowABlend;
    public bool m_bShowFPS;
    
    public string m_szMapName;
    public MemMappedId m_stMemMappedID[_VIEW_CELL_Y_COUNT][_VIEW_CELL_X_COUNT];
    
    public Vector!(Actor) ActorList, FreeActorList;
    public Vector!(Magic) MagicList;
    public Vector!(Magic) GroundMagicList;
    public Vector!(PGroundItem) MapItemList;
    
    //CBMMp3 m_xBGM;
    public Particle m_xParticles;
    public ImageHandler m_xImage;
    public MirMap m_xMap;
    public GameInterface m_xInterface;
    public MyHero m_xMyHero;
    //HBRUSH m_hBrush;
    public IntPoint m_ptMousePos;
    public IntPoint m_ptCurrTile;
    public bool m_bRender;

    public DayState m_bDayState;
    public FogState m_bFogState;
    public LightFog m_xLightFog;

    public Mist m_xMist;
    public SnowSystem m_xSnow;
    public RainSystem m_xRain;
    public FlyingTail m_xFlyingTail;
    public Smoke m_xSmoke;
    
    public Electric m_xElec;
    
    //CNoticeBox m_xNotice;
    
    public Actor m_pxMouseTargetActor;
    public Actor m_pxMouseOldTargetActor;
    public Actor m_pxSavedTargetActor;
    
    public PacketQueue m_xWaitPacketQueue; 
    public PacketQueue m_xWaitDefaultPacketQueue;  
    
    public int m_wInputDelayTime;
    public int m_wCurrInputDelayTime;
    
    public float m_fDarkRate;
    public bool m_bFogChanging;
    public TickDuration m_dwLastFogTick;
    
    public ubyte m_fTileLightRed;
    public ubyte m_fTileLightGreen;
    public ubyte m_fTileLightBlue;
    
    public ushort m_wShadowClr[800];
    
    //D3DMATRIX m_matWorld;
    
    public bool m_bShowShine;   
    public TickDuration m_dwLastShineTick;
    public int m_wShineCurrDelay;
    public int m_bCurrShineFrame;
    //D3DVERTEX m_avBillboard[4];


    public int m_wNPCWndPosX, m_wNPCWndPosY;

    public SystemMessage m_xSysMessage;
    public HintMessage m_xHint;

    private int nLoopTime;
    public ALLEGRO_BITMAP* m_pddsBackBuffer;

    private ALLEGRO_SHADER* shader;



    public bool DrawWithImagePerLineClipRgn(int nX, int nY, int nXSize, int nYSize, ushort[] pwSrc, ushort wClipWidth, ushort wClipHeight)
    {
        ALLEGRO_LOCKED_REGION* lr;
        IntRectangle rc;
        
        int nWidth = nXSize;
        int nHeight = nYSize;
        int nXOffset = 0;
        int nYOffset = 0;
        int nStartX = 0;
        int nStartY = 0;
        int nEndX = wClipWidth  - 1;
        int nEndY = wClipHeight - 1;

        if ( m_pddsBackBuffer !is null )
        {
            if (nX < nStartX )
            { 
                nXOffset = nStartX - nX;
                nWidth = nXSize - nXOffset;
            }
            if ( (nX+nXSize-1) > nEndX )
                nWidth = nEndX - nX - nXOffset + 1;       
            if ( nY < nStartY )
            { 
                nYOffset = nStartY - nY;
                nHeight = nYSize - nYOffset;
            }
            if ( (nY+nYSize-1) > nEndY )
                nHeight = nEndY - nY - nYOffset + 1;
            
            if ( (nWidth > 0) && (nHeight > 0) )
            {
                rc = IntRectangle(nXOffset, nYOffset, nXOffset + nWidth, nYOffset + nHeight);

                lr = al_lock_bitmap(m_pddsBackBuffer, ALLEGRO_PIXEL_FORMAT.ALLEGRO_PIXEL_FORMAT_RGB_565, ALLEGRO_LOCK_WRITEONLY);
                if (lr is null || lr.data is null /*|| lr.pitch <= 0*/)
                    return false;

                auto dest = cast(ushort*)lr.data;
                
                for ( int y = rc.getTop(); y < rc.getBottom(); y++ )
                {
                    memcpy(&dest[((y+nY) * (lr.pitch >> 1)) + (nX + rc.getLeft())], &pwSrc[y * nXSize + rc.getLeft()], rc.getWidth()*ushort.sizeof);
                }

                al_unlock_bitmap(m_pddsBackBuffer);
            }

            return true;
        }
        return false;
    }

    public ALLEGRO_BITMAP* GetObjs(int wunit, int idx)
    {
        if (wunit >= 0 && wunit <= 9)
            return m_xImage[_IMAGE_OBJECT1 + wunit][idx];
        else
            return m_xImage[_IMAGE_OBJECT1][idx];
    }
    
    public ALLEGRO_BITMAP* GetObjsEx(int wunit, int idx, ref int px, ref int py)
    {
        ALLEGRO_BITMAP* bmp;
        ImageInfo imgi;
        
        if (wunit >= 0 && wunit <= 9)
            bmp = m_xImage[_IMAGE_OBJECT1 + wunit].GetCachedImageEx(idx, imgi);
        else
            bmp = m_xImage[_IMAGE_OBJECT1].GetCachedImageEx(idx, imgi);
        
        px = imgi.PosX;
        py = imgi.PosY;
        return bmp;
    }


    
    public this(Game game)
    {
        super(game, SceneType.PlayGame);

        // Allocate objects.
        m_xImage = new ImageHandler;

        m_xInterface = new GameInterface;

        m_xMyHero = new MyHero;
        m_xMap = new MirMap;
        
        m_xLightFog = new LightFog;
        m_xMist = new Mist;
        m_xFlyingTail = new FlyingTail;
        m_xSmoke = new Smoke;
        m_xSnow = new SnowSystem;
        m_xRain = new RainSystem;
        m_xElec = new Electric;
    }

    public override void Initialize()
    {
        m_pddsBackBuffer = al_create_bitmap((_VIEW_CELL_X_COUNT*_CELL_WIDTH), (_VIEW_CELL_Y_COUNT*_CELL_HEIGHT));
        shader = create_shader();

        m_bTileView = false;
        m_bObj1View = false;
        m_bObj2View = false;
        m_bCellView = false;
        m_bStatusView = false;
        m_bStopPtView = false;
        m_bRender = false;
        m_bShowSnow = false;
        m_bShowMist = false;
        m_bShowRain = false;
        m_bShadowABlend = false;
        
        m_bShowFPS = false;
        
        m_ptMousePos = IntPoint.zero;
        m_ptCurrTile = IntPoint.zero;
        m_stMemMappedID = m_stMemMappedID.init;
        
        m_bDayState = DayState.Day;
        m_bFogState = FogState.Day;
        
        m_pxMouseTargetActor = null;     // ÇöÀç ¸¶¿ì½º°¡ °¡¸®Å°´Â °÷ÀÇ Å¸°Ù¾×ÅÍ.
        m_pxMouseOldTargetActor = null;     // ÀúÀåµÇ¾îÀÖ´Â Å¸°Ù¾×ÅÍ.
        m_pxSavedTargetActor = null;
        
        m_fTileLightRed = 255;
        m_fTileLightGreen = 230;
        m_fTileLightBlue = 180;
        
        m_fDarkRate = 255.0f;
        m_wInputDelayTime = 0;
        m_wCurrInputDelayTime = 0;
        
        m_wNPCWndPosX = 0;
        m_wNPCWndPosY = 0;
        
        m_wShadowClr = m_wShadowClr.init;
        
        m_bShowShine = false;    
        m_dwLastShineTick = Clock.currSystemTick();
        m_wShineCurrDelay = 0;
        m_bCurrShineFrame = 0;
        
        // PDS:
        /*D3DVECTOR vNorm(0, 0, -1);
        m_avBillboard[0]  = D3DVERTEX(D3DVECTOR(-0.5f, 0.5f, 0), vNorm, 0, 0);
        m_avBillboard[1]  = D3DVERTEX(D3DVECTOR(-0.5f,-0.5f, 0), vNorm, 0, 1);
        m_avBillboard[2]  = D3DVERTEX(D3DVECTOR( 0.5f, 0.5f, 0), vNorm, 1, 0);
        m_avBillboard[3]  = D3DVERTEX(D3DVECTOR( 0.5f,-0.5f, 0), vNorm, 1, 1);*/
        
        m_szMapName = m_szMapName.init;
        
        
        m_xImage.InitAllImage();
        m_xInterface.reset();
        
        m_xMyHero.InitActor();
        m_xMap.InitMapHandler();
        
        m_xLightFog.Init(al_map_rgb(255, 255, 255));
        
        m_xMist.initMist();
        m_xMist.setupMist();
        
        m_xFlyingTail.InitSystem();
        m_xFlyingTail.SetupSystem();
        
        m_xSmoke.InitSystem();
        m_xSmoke.SetupSystem();
        
        m_xSnow.InitSystem();
        m_xSnow.SetupSnowSystem();
        
        m_xRain.InitSystem();
        m_xRain.SetupRainSystem();
        
        //m_xElec.InitElec();
        
        //m_hBrush = CreateSolidBrush(RGB(200, 150, 100)); // TODO:
    }
    
    public override void Finalize()
    {
        if (m_pddsBackBuffer !is null)
        {
            al_destroy_bitmap(m_pddsBackBuffer);
            m_pddsBackBuffer = null;
        }
        if (shader !is null)
        {
            al_destroy_shader(shader);
            shader = null;
        }

        int nCnt, nLeftMsgCnt;
        PPacketMsg packet;
        
        packet = null;
        nLeftMsgCnt = m_xWaitPacketQueue.count();
        
        // ½×¿©ÀÖ´Â ÆÐÅ¶À» Áö¿î´Ù.
        if ( nLeftMsgCnt > 0 )
        {
            for ( nCnt = 0; nCnt < nLeftMsgCnt; nCnt++ )
            {
                packet = m_xWaitPacketQueue.dequeue();
                if ( packet !is null )
                {
                    destroy(packet);
                }
            }
        }
        
        packet = null;
        nLeftMsgCnt = m_xWaitDefaultPacketQueue.count();
        
        // ½×¿©ÀÖ´Â ÆÐÅ¶À» Áö¿î´Ù.
        if ( nLeftMsgCnt > 0 )
        {
            for ( nCnt = 0; nCnt < nLeftMsgCnt; nCnt++ )
            {
                packet = m_xWaitDefaultPacketQueue.dequeue();
                if ( packet !is null )
                {
                    destroy(packet);
                }
            }
        }
        
        // PDS:
        //D3DWILTextr_InvalidateAllTextures();
        //D3DWILTextr_DestroyAllTextures();
        //DeleteObject(m_hBrush);
        m_xImage.DeleteAllImage();
        m_xMap.DestroyMapHandler();
        m_xInterface = null;
        m_xMyHero.DestroyActor();
        
        m_xMist.destroyMist();
        m_xSnow.DestroySystem();
        m_xRain.DestroySystem();
        m_xFlyingTail.DestroySystem();
        m_xSmoke.DestroySystem();
        m_xElec.DestroyElec();
        
        ActorList.clear();
        MagicList.clear();
        GroundMagicList.clear();
        MapItemList.clear();
        
        MySocket.DisconnectToServer();
    }
    
    public override void OpenScene()
    {
        int nCnt;

        auto display = al_get_current_display();
        if (display is null)
            throw new Exception("Could not get current display!");

        bool resized = al_resize_display(display, SCREENWIDTH, SCREENHEIGHT);
        if (resized)
            guiMan.resizeToDisplay();

/*
        CHAR szSetup[MAX_PATH];
        ZeroMemory(szSetup, MAX_PATH);
        jRegGetKey(_T("Software\\WEMADE Entertainment\\¹Ì¸£ÀÇÀü¼³2"), _T("setup path"), (LPBYTE)szSetup);
        for ( nCnt = strlen(szSetup); nCnt >= 0; nCnt--)
        {
            if ( szSetup[nCnt] == '\\' )
            {
                szSetup[nCnt+1] = NULL;
                break; 
            }
        }
*/


        //m_xLightFog.Init(al_map_rgb(255, 255, 255));
        m_xImage.LoadAllImage();
        m_xInterface.createInterface(m_xImage);
        //m_xNotice.Load(&m_xImage.m_xImageList[_IMAGE_INTER]); // TODO:
        
        MySocket.ConnectToServer(g_szServerIP, g_nServerPort);
        
        /*  for ( nCnt = 0; nCnt < m_xImage.m_xImageList[_IMAGE_MAGIC].m_stNewWixImgaeInfo.nIndexCount; nCnt++)
    {
        if ( m_xImage.m_xImageList[_IMAGE_MAGIC].NewSetIndex(nCnt) )
        {
            D3DWILTextr_CreateEmptyTexture(m_xImage.m_xImageList[_IMAGE_MAGIC].m_szWilFileName, nCnt, 
                                           m_xImage.m_xImageList[_IMAGE_MAGIC].m_lpstNewCurrWilImageInfo.shWidth,
                                           m_xImage.m_xImageList[_IMAGE_MAGIC].m_lpstNewCurrWilImageInfo.shHeight,
                                           (WORD*)m_xImage.m_xImageList[_IMAGE_MAGIC].m_pbCurrImage, D3DTEXTR_TRANSPARENTBLACK);
        }
    }
    for ( nCnt = 0; nCnt < m_xImage.m_xImageList[_IMAGE_MONMAGIC].m_stNewWixImgaeInfo.nIndexCount; nCnt++)
    {
        if ( m_xImage.m_xImageList[_IMAGE_MONMAGIC].NewSetIndex(nCnt) )
        {
            D3DWILTextr_CreateEmptyTexture(m_xImage.m_xImageList[_IMAGE_MONMAGIC].m_szWilFileName, nCnt, 
                                           m_xImage.m_xImageList[_IMAGE_MONMAGIC].m_lpstNewCurrWilImageInfo.shWidth,
                                           m_xImage.m_xImageList[_IMAGE_MONMAGIC].m_lpstNewCurrWilImageInfo.shHeight,
                                           (WORD*)m_xImage.m_xImageList[_IMAGE_MONMAGIC].m_pbCurrImage, D3DTEXTR_TRANSPARENTBLACK);
        }
    }
*/
        /*  // ¾ÆÀÌÅÛ ¹ÝÂ¦°Å¸² ÅØ½ºÃç.
    for ( nCnt = 0; nCnt < 10; nCnt++)
    {
        if ( m_xImage.m_xImageList[_IMAGE_PROGUSE].NewSetIndex(nCnt+40) )
        {
            D3DWILTextr_CreateEmptyTexture(m_xImage.m_xImageList[_IMAGE_PROGUSE].m_szWilFileName, nCnt+40, 
                                           m_xImage.m_xImageList[_IMAGE_PROGUSE].m_lpstNewCurrWilImageInfo.shWidth,
                                           m_xImage.m_xImageList[_IMAGE_PROGUSE].m_lpstNewCurrWilImageInfo.shHeight,
                                           (WORD*)m_xImage.m_xImageList[_IMAGE_PROGUSE].m_pbCurrImage, D3DTEXTR_TRANSPARENTBLACK);
            m_lpddsShineTextr[nCnt] = D3DWILTextr_RestoreEx(m_xImage.m_xImageList[_IMAGE_PROGUSE].m_szWilFileName, nCnt+40, g_xMainWnd.Get3DDevice());
        }
    }
*/
        // PDS: This all done in Initialize... -------------
        //m_xMist.initMist();
        //m_xMist.setupMist();
        
        //m_xSnow.InitSystem();
        //m_xSnow.SetupSnowSystem();
        
        //m_xRain.InitSystem();
        //m_xRain.SetupRainSystem();
        
        //m_xFlyingTail.InitSystem();
        //m_xFlyingTail.SetupSystem();
        
        //m_xSmoke.InitSystem();
        //m_xSmoke.SetupSystem(); 
        
        //m_xElec.InitElec();
        //m_xElec.SetupElec();  
        // -------------------------------------------------
        
        m_stMemMappedID = m_stMemMappedID.init;
        
        //SendMessage(g_xChatEditBox.GetSafehWnd(),EM_SETPASSWORDCHAR, NULL, NULL);
        //g_xChatEditBox.SetLimitText(90);
        
        // TODO:
        ushort wShadowClr;// = g_xMainWnd.ConvertColor24To16(RGB(20, 20, 20));
        for ( nCnt = 0; nCnt < 800; nCnt++ )
        {
            m_wShadowClr[nCnt] = wShadowClr;
        }
        
        m_xMap.LoadMapImage(m_xImage);
        
        // TODO:
        //SetTimer(g_xMainWnd.GetSafehWnd(), WM_USER + 5000, 10, NULL); // Temp
        
        
        
        
        // PDS: Test code below..
        string mapName = "0";
        int ActorX = 449;
        int ActorY = 432;
        
        m_xMap.SetStartViewTile(ActorX - _GAPY_TILE_CHAR_MAP, ActorY - _GAPY_TILE_CHAR_MAP);
        LoadMapChanged(mapName);
        
        Feature stFeature;
        FeatureEx stFeatureEx;
        stFeature.Dress = 5;
        stFeature.Gender = _GENDER_MAN;
        stFeature.Hair = 3;
        stFeature.Weapon = 3;
        
        m_xMyHero.m_szName = "Damian";
        m_xMyHero.m_dwIdentity  = 12345;
        m_xMyHero.m_bLightSize  = 6;
        m_xMyHero.m_bJob = _JOB_JUNSA;

        m_xMyHero.m_stAbility.HP = 50;
        m_xMyHero.m_stAbility.MaxHP = 500;
        
        m_xMyHero.m_stAbility.MP = 400;
        m_xMyHero.m_stAbility.MaxMP = 500;
        
        m_xMyHero.m_stAbility.Exp = 800;
        m_xMyHero.m_stAbility.MaxExp = 1000;
        
        m_xMyHero.m_stAbility.Weight = 10;
        m_xMyHero.m_stAbility.MaxWeight = 100;
        
        //m_xMyHero.m_stAbility.AC = MakeWord(10, 20);
        //m_xMyHero.m_stAbility.SC = MakeWord(100, 200);
        
        ubyte bDir = 4;
        m_xMyHero.Create(m_xImage, Motion.Stand, bDir, cast(ushort)ActorX, cast(ushort)ActorY, stFeature, stFeatureEx);
        m_xMyHero.SetMapHandler(m_xMap);
        
        //Magic pxMagic;
        //pxMagic = new Magic;
        //pxMagic.CreateMagic(_SKILL_LIGHTENING, m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, null, m_xMyHero.m_dwIdentity);
        //MagicList.add(pxMagic);
        
        
        //pxMagic = new Magic;
        //pxMagic.CreateMagic(_SKILL_HEALLING, ActorX+1, ActorY+1, ActorX+1, ActorY+1, null, 0);
        //MagicList.add(pxMagic); 
        
        m_wInputDelayTime = 2300;
        m_wCurrInputDelayTime = 0;
        m_xMyHero.m_wABlendCurrDelay = 0;
        m_xMyHero.m_wABlendDelay = 2300;
        
        //SoundMan.PlayBGM(mapName);
        
        m_bDayState = DayState.Dawn;
        m_bFogState = FogState.Dawn;
        m_bFogChanging = true;
        
        m_bShowSnow = true;

        m_bStatusView = true;
        m_bShowFPS = true;
        m_bRender = true;
    }
    
    public override void CloseScene()
    {
        m_bRender = false;

        SoundMan.StopAllSound;
        SoundMan.StopBGM;
    }
    
    public override void PlayScene()
    {
        const clear_color = al_map_rgba_f(0.0, 0.0, 0.0, 0.0);

        int i;
        Actor actor;
        Hero hero;
        Magic magic;
        ElecMagic elecMagic;

        if ( m_bRender )
        {
            // ¸ÊÀ» ±×¸°´Ù.
            //Clear(0);
            if (m_xMap.isDirty())
            {
                DrawWithImagePerLineClipRgn(
                    m_xMap.m_rcView.getLeft()+_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                    m_xMap.m_rcView.getTop()+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY,
                    m_xMap.m_rcView.getWidth(),
                    m_xMap.m_rcView.getHeight(),
                    m_xMap.m_wSavedMapBuffer, _CLIP_WIDTH, _CLIP_HEIGHT);
                m_xMap.setDirty(false);
            }
            al_draw_bitmap(m_pddsBackBuffer, 0, 0, 0);

            al_hold_bitmap_drawing(true);
            RenderObject(nLoopTime);
            al_hold_bitmap_drawing(false);
            RenderMapTileGrid(); // For Debug 


            if ( m_bShowMist )
            {
                m_xMist.renderMist();
            }

            if ( m_bShowSnow )          
            {
                m_xSnow.RenderSystem();
            }
            
            if ( m_bShowRain )          
            {
                m_xRain.RenderSystem();
            }

            m_xFlyingTail.RenderSystem();

            m_xSmoke.RenderSystem();        

            //m_xElec.RenderElec();

            //m_xLightFog.SetLightRadiusWithElipse(200, 200, 3, 3, 
            //                                     255, 0, 0);

            m_xLightFog.ShowLightFog();
            
            m_xMyHero.ShowMessage(nLoopTime);
            m_xMyHero.DrawHPBar();

            while (true)
            {
                if (i >= ActorList.count()) break;
                actor = ActorList[i];
                
                switch ( actor.m_stFeature.Gender )
                {
                    case _GENDER_MAN:
                    case _GENDER_WOMAN:
                    {
                        hero = cast(Hero)actor;
                        hero.ShowMessage(nLoopTime);
                        hero.DrawHPBar();
                        break;
                    }

                    case _GENDER_NPC:
                    case _GENDER_MON:
                    {
                        //actor.ShowMessage(nLoopTime);
                        actor.DrawHPBar();
                        break;
                    }

                    default: break;
                }
                
                i++;
            }
            
            DropItemShow();
            //RenderShine(nLoopTime);

            while (true)
            {
                if (i >= MagicList.count) break;
                magic = MagicList[i];
                
                if ( magic.m_bMagicNum == _SKILL_SHOOTLIGHTEN )
                {
                    elecMagic = cast(ElecMagic)magic;
                    elecMagic.DrawMagic();
                }
                else
                {
                    magic.DrawMagic();
                }
                
                i++;
            }  
            
            if ( m_pxMouseTargetActor !is null )
            {
                m_pxMouseTargetActor.DrawName();
                m_pxMouseTargetActor.DrawHPBar();
            }

            m_xInterface.render(nLoopTime, m_ptMousePos);

            // Show game information.
            showStatus(0, 0);
        }
        else
        {
            al_clear_to_color(clear_color);
        }

        //const auto alpha = 125/255.0f;
        //const auto r = 128/255;
        //const gray_color = al_map_rgba_f(0.299, 0.587, 0.114, 0.5);
        //const red_color = al_map_rgba_f(1.0, 0, 0, 0.5);

        /*ALLEGRO_BITMAP* targ = al_get_target_bitmap();
        if (targ !is null)
            al_draw_tinted_bitmap(targ, gray_color, 0, 0, 0);*/

        /*ALLEGRO_DISPLAY* display = al_get_current_display();
        if (display !is null)
        {
            ALLEGRO_BITMAP* backbuffer = al_get_backbuffer(display);
            if (backbuffer !is null)
                al_draw_tinted_bitmap(backbuffer, gray_color, 0, 0, 0);
        }*/

        //al_draw_filled_rectangle(0, 0, SCREENWIDTH, SCREENHEIGHT, gray_color);

        if (shader !is null)
            al_use_shader(shader);

        //g_xMainWnd.DrawWithGrayBackBuffer();
        // TODO:
        //m_xNotice.RenderMessageBox(nLoopTime);
    }

    public override void KeyDown(int keycode)
    {
        switch (keycode)
        {
            case ALLEGRO_KEY_LEFT:
            {
                ALLEGRO_TRANSFORM identity, world;

                al_identity_transform(&world);

                al_translate_transform(&world, -2.0f, 0);
                
                al_use_transform(&world);

                //m_xMap.SetMovedTileBuffer(-1, 0);
                break;
            }
                
            case ALLEGRO_KEY_RIGHT:
            {
                m_xMap.SetMovedTileBuffer(1, 0);
                break;
            }

            case ALLEGRO_KEY_UP:
            {
                m_xMap.SetMovedTileBuffer(0, -1);
                break;
            }

            case ALLEGRO_KEY_DOWN:
            {
                m_xMap.SetMovedTileBuffer(0, 1);
                break;
            }
                
            default: break;
        }
    }

    public override void KeyUp(int keycode)
    {
        //m_xInterface.OnKeyUp(wParam, lParam);
    }

    public override void MouseDown(uint button, in IntPoint pt)
    {
        m_ptMousePos = pt;
        m_ptCurrTile.setX( m_xMap.m_shStartViewTileX + (m_ptMousePos.getX() - _VIEW_CELL_X_START) / TILE_WIDTH );
        m_ptCurrTile.setY( m_xMap.m_shStartViewTileY + (m_ptMousePos.getY() - _VIEW_CELL_Y_START) / TILE_HEIGHT );

        if (button == 2)
        {
            m_pxSavedTargetActor = null;
            
            m_xMyHero.OnRButtonDown(m_ptMousePos);
            return;
        }

        IntPoint ptTaretTilePos;
        
        // °ÔÀÓµ¥ÀÌÅ¸°¡ ·ÎµåµÇ¾ú´ÂÁö...
        // TODO:
        /*if(m_xNotice.IsActive())
        {
            m_xNotice.OnButtonDown(m_ptMousePos);
        }*/
        
        if ( !m_bRender ) return;
        
        m_pxSavedTargetActor = null;

        if ( !m_xInterface.OnButtonDown(button, m_ptMousePos) )
        {
            // ÀÎÅÍÆäÀÌ½º¿¡¼­ ÇÏ´ÂÀÏÀÌ ¾øÀ»¶§.
            
            // 1. ¾ÆÀÌÅÛÀ» ¶³¾î¶ß¸®±â.
            if ( m_xInterface.m_stCommonItem.bSetted && !m_xInterface.m_stCommonItem.bWaitResponse && !m_xInterface.m_stCommonItem.bIsEquipItem )
            {
                auto iname = m_xInterface.m_stCommonItem.xItem.m_stItemInfo.S.Name.idup;
                MySocket.SendItemIndex(CM_DROPITEM, m_xInterface.m_stCommonItem.xItem.m_stItemInfo.Serial, iname);
                m_xInterface.m_stCommonItem.bWaitResponse = true;
                return;
            }

            // 2. ¸Ê¾ÆÀÌÅÛ ÁÝ±â.
            // TODO:
            /*if ( m_stMapItemList.GetCounter() != 0 )
            {
                m_stMapItemList.MoveCurrentToTop();
                LPGROUNDITEM pstItem;
                
                for ( INT nCnt = 0; nCnt < m_stMapItemList.GetCounter(); nCnt++ )
                {
                    pstItem = m_stMapItemList.GetCurrentData();
                    
                    if ( pstItem.shTileX == m_ptCurrTile.x && pstItem.shTileY == m_ptCurrTile.y && pstItem.shTileX == m_xMyHero.m_wPosX && pstItem.shTileY == m_xMyHero.m_wPosY )
                    {
                        g_xClientSocket.SendPickUp(pstItem.shTileX, pstItem.shTileY);
                        return 0L;
                    }
                    m_stMapItemList.MoveNextNode();
                }
            }*/
            
            if ( m_pxMouseTargetActor !is null )
            {
                if ( !m_pxMouseTargetActor.m_bIsDead )
                {
                    // °ø°Ý´ë»ó ActorÁ¤ÇÏ±â.
                    m_pxSavedTargetActor = m_pxMouseTargetActor;
                }

                ptTaretTilePos.setX( m_pxMouseTargetActor.m_wPosX );
                ptTaretTilePos.setY( m_pxMouseTargetActor.m_wPosY );
                if ( m_pxMouseTargetActor.m_stFeature.Gender == _GENDER_NPC )
                {
                    MySocket.SendNPCClick(m_pxMouseTargetActor.m_dwIdentity);
                    m_pxSavedTargetActor = null;
                }
                else
                {
                    m_xMyHero.OnLButtonDown(m_ptMousePos, m_pxMouseTargetActor.m_dwIdentity, m_pxMouseTargetActor.m_bIsDead, &ptTaretTilePos);
                }
            }
            else
            {
                m_xMyHero.OnLButtonDown(m_ptMousePos);
            }
        }
        
        return;
    }

    public override void MouseUp(uint button, in IntPoint pt)
    {
        m_ptMousePos = pt;
        m_ptCurrTile.setX( m_xMap.m_shStartViewTileX + (m_ptMousePos.getX() - _VIEW_CELL_X_START) / TILE_WIDTH );
        m_ptCurrTile.setY( m_xMap.m_shStartViewTileY + (m_ptMousePos.getY() - _VIEW_CELL_Y_START) / TILE_HEIGHT );

        if (button == 1)
        {
            // TODO:
            /*if(m_xNotice.IsActive())
            {
                if(m_xNotice.OnButtonUp(m_ptMousePos))
                {
                    // OK Button Click
                    m_xNotice.HideMessageBox();
                    Clear(RGB(0,0,0));
                    // Start Game From Here
                }
            }
            else*/
                m_xInterface.OnButtonUp(button, m_ptMousePos);
        }
        return;
    }

    public override void MouseMove(in IntPoint pt)
    {
        m_ptMousePos = pt;
        m_ptCurrTile.setX( m_xMap.m_shStartViewTileX + (m_ptMousePos.getX() - _VIEW_CELL_X_START) / TILE_WIDTH );
        m_ptCurrTile.setY( m_xMap.m_shStartViewTileY + (m_ptMousePos.getY() - _VIEW_CELL_Y_START) / TILE_HEIGHT );

        // TODO:
        /*if (m_xNotice.IsActive())
        {
            m_xNotice.MoveWnd(m_ptMousePos);
        }
        else*/
        {
            m_xInterface.OnMouseMove(m_ptMousePos);
        }
    }
    
    public override void UpdateScene()
    {
        int i;
        Actor actor;
        Magic magic;
        ElecMagic elecMagic;


        nLoopTime = std.random.uniform(10, 20);

        bool bIsMoveTime = false;
        static ushort wMoveTime = 0;
        static uint dwReceiveTime = 0;
        
        wMoveTime += nLoopTime;
        m_wCurrInputDelayTime += nLoopTime;
        
        if ( nLoopTime < 10000 ) dwReceiveTime += nLoopTime;
        if ( m_wCurrInputDelayTime >= m_wInputDelayTime )
        {
            m_wCurrInputDelayTime = 0;
            m_wInputDelayTime = 0;
        }
        if ( wMoveTime > 100 )
        {
            bIsMoveTime = true;
            wMoveTime = 0;
        }
        if ( !m_bRender && dwReceiveTime > 100000 )
        {
            // TODO: ...
            //MessageBox(g_xMainWnd.GetSafehWnd(), "·Î±×¿Â Á¤º¸¸¦ ¹Þ´Âµ¥ ½ÇÆÐÇß½À´Ï´Ù. ÇÁ·Î±×·¥À» Á¾·áÇÕ´Ï´Ù.", "", MB_OK);
            //PostQuitMessage(NULL);
            dwReceiveTime = 0;
        }


        if ( m_bRender )
        {
            m_xInterface.update(nLoopTime);

            m_xLightFog.ClearSavedLightColor();
            
            m_xMyHero.UpdateMotionState(nLoopTime, bIsMoveTime);
            
            m_pxMouseTargetActor = null;
            CheckMappedData(nLoopTime, bIsMoveTime);
            AutoTargeting();

            i = 0;
            while (true)
            {
                if (i >= MagicList.count) break;
                magic = MagicList[i];

                if ( magic.m_bMagicNum == _SKILL_SHOOTLIGHTEN )
                {
                    elecMagic = cast(ElecMagic)magic;
                    elecMagic.UpdateMagic(nLoopTime);
                    
                    if ( elecMagic.m_bActiveState == _MAGIC_FINISH )
                    {
                        MagicList.deleteAt(i);
                        delete elecMagic;
                        elecMagic = null;
                    }
                }
                else
                {
                    magic.UpdateMagic(nLoopTime);
                    if ( magic.m_bActiveState == _MAGIC_FINISH )
                    {
                        MagicList.deleteAt(i);
                        delete magic;
                        magic = null;
                    }
                }

                i++;
            }

                
                
            
            if ( m_bShowMist )
            {
                m_xMist.progressMist();
            }

            if ( m_bShowSnow )          
            {
                m_xSnow.UpdateSystem(nLoopTime);
            }
            
            if ( m_bShowRain )          
            {
                m_xRain.UpdateSystem(nLoopTime);
            }
            
            m_xFlyingTail.UpdateSystem(nLoopTime);
            
            m_xSmoke.UpdateSystem(nLoopTime);     
            
            //m_xElec.UpdateElec(400, 300, 0, 0);


            
            if ( m_pxMouseTargetActor !is null )
            {
                if ( m_pxMouseOldTargetActor !is m_pxMouseTargetActor )
                {
                    if ( m_pxMouseTargetActor.m_szName.length == 0 )
                        MySocket.SendQueryName(m_pxMouseTargetActor.m_dwIdentity, m_pxMouseTargetActor.m_wPosX, m_pxMouseTargetActor.m_wPosY);
                }
                
                m_pxMouseOldTargetActor = m_pxMouseTargetActor;
            }
            
            if ( m_wNPCWndPosX && m_wNPCWndPosY && ( abs(m_wNPCWndPosX-m_xMyHero.m_wPosX) > 5 || abs(m_wNPCWndPosY-m_xMyHero.m_wPosY) > 5) )
            {
                //CloseNPCWindow(); // TODO:
            }
        }
        

        if (!m_bRender) return;

        immutable curtime = Clock.currSystemTick();

        if (m_bFogChanging)
        {
            if ((curtime - m_dwLastFogTick).msecs >= 100)
            {
                m_dwLastFogTick = curtime;

                float fDstDarkRate;
                final switch ( m_bFogState )
                {
                    case FogState.Dawn:
                    {
                        fDstDarkRate = 50.0f;
                        break;
                    }
                    case FogState.Day:
                    {
                        fDstDarkRate = 255.0f;
                        break;
                    }
                    case FogState.Night:
                    {
                        fDstDarkRate = 10.0f;
                        break;
                    }
                }
                
                if      ( m_fDarkRate > fDstDarkRate )  m_fDarkRate -= 0.5f;
                else if ( m_fDarkRate < fDstDarkRate )  m_fDarkRate += 0.5f;
                else    
                {
                    m_bFogChanging = false;
                }

                immutable dwFogColor = al_map_rgb_f(m_fDarkRate/255.0f, m_fDarkRate/255.0f, m_fDarkRate/255.0f);
                m_xLightFog.ChangeLightColor(dwFogColor);
            }
        }
    }

    public void DropItemShow()
    {
        const itemname_back_color = al_map_rgba(0, 0, 0, 0);
        const itemname_front_color = al_map_rgba(255, 255, 125, 0);

        if ( MapItemList.count() > 0 )
        {
            for ( int i = 0; i < MapItemList.count(); i++ )
            {
                PGroundItem gitem = MapItemList[i];
                
                if ( gitem.TileX == m_ptCurrTile.getX() && gitem.TileY == m_ptCurrTile.getY() )
                {
                    IntPoint size = MyPen.measureText(gitem.Name);
                    //int nCenterX, nCenterY;
                    //m_xMap.GetScrnPosFromTilePos(gitem.TileX, gitem.TileY, nCenterX, nCenterY);

                    int nCenterX = (gitem.TileX-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX+_CELL_WIDTH /2;
                    int nCenterY = (gitem.TileY-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY+_CELL_HEIGHT/2-12;

                    // draw filled rectangle color..
                    auto tint_color = al_map_rgba(100, 100, 100, 125);

                    al_draw_filled_rectangle(nCenterX-size.getX()/2, nCenterY-7, 
                                             nCenterX+size.getX()/2, nCenterY+8, 
                                             tint_color);

                    MyPen.drawShadowText(nCenterX-size.getX()/2, nCenterY, itemname_front_color, itemname_back_color, gitem.Name);
                    
                    break;
                }
            }
        }   
    }

    public void LoadMapChanged(string mapName)
    {
        m_xMap.LoadMapData(mapName);
        m_xMap.LoadNewMapBuffer();

        m_stMemMappedID = m_stMemMappedID.init;

        auto fogColor = m_xMap.Header.cFogColor;
        ALLEGRO_COLOR dwFogColor;
        switch (fogColor)
        {
            case 0: dwFogColor = _FOG_COLOR_TYPE0; break;
            case 1: dwFogColor = _FOG_COLOR_TYPE1; break;
            case 2: dwFogColor = _FOG_COLOR_TYPE2; break;
            case 3: dwFogColor = _FOG_COLOR_TYPE3; break;
            default: dwFogColor = _FOG_COLOR_TYPE0; break;
        }
        m_xLightFog.ChangeLightColor(dwFogColor);
    }
    
    public void AutoTargeting()
    {
        static ubyte bLastDir = _DIRECTION_LIST_1;
        
        if ( !m_xMyHero.m_bMotionLock && !m_xMyHero.m_bInputLock && m_pxSavedTargetActor )
        {
            int shLeftMsgCnt = m_xMyHero.m_xPacketQueue.count();
            if ( shLeftMsgCnt > 0 )
            {
                if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE ) m_xMyHero.SetMotionState(Motion.Stand, m_xMyHero.m_bCurrDir);
                else m_xMyHero.SetMotionState(Motion.HorseStand, m_xMyHero.m_bCurrDir);
                m_xMyHero.UpdatePacketState();
                return;
            }
            
            IntPoint ptTargetTile = IntPoint.zero;
            ubyte bDir = m_xMyHero.CalcDirection(m_pxSavedTargetActor.m_wPosX, m_pxSavedTargetActor.m_wPosY);
            
            if ( m_pxSavedTargetActor.m_bIsDead )
                return;
            
            if ( (m_pxSavedTargetActor.m_stFeature.Gender == _GENDER_MON && m_pxSavedTargetActor.m_bCurrMtn == MonsterMotion.Die) ||
                (m_pxSavedTargetActor.m_stFeature.Gender <= _GENDER_WOMAN && m_pxSavedTargetActor.m_bCurrMtn == Motion.Die) )
                return;
            
            
            if ( cast(int)(sqrt(cast(double)(m_xMyHero.m_wPosX-m_pxSavedTargetActor.m_wPosX)*(m_xMyHero.m_wPosX-m_pxSavedTargetActor.m_wPosX) +   (m_xMyHero.m_wPosY-m_pxSavedTargetActor.m_wPosY)*(m_xMyHero.m_wPosY-m_pxSavedTargetActor.m_wPosY)))
                < 2 )
            {
                if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE && !m_pxSavedTargetActor.m_bIsDead )
                {
                    // °ø°ÝÇÑ´Ù.
                    ptTargetTile.set(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY);
                    m_xMyHero.SetMotionState(Motion.OneHSwing, bDir, m_pxSavedTargetActor.m_dwIdentity, m_pxSavedTargetActor.m_bIsDead, &ptTargetTile);
                }
            }
            // Actor°¡ ÀÖ´Â ¹æÇâÀ¸·Î ÀÌµ¿ °¡´ÉÇÑ°¡?(¸Ê¼Ó¼ºÃ¼Å©) 
            else if ( m_xMap.GetNextTileCanMove(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, bDir, 1, ptTargetTile) )
            {
                // 1Å¸ÀÏ ÀÌµ¿ÇÑ´Ù.
                if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE )
                {
                    m_xMyHero.SetMotionState(Motion.Walk, bDir);
                }
                else
                {
                    m_xMyHero.SetMotionState(Motion.HorseWalk, bDir);
                }
                bLastDir = bDir;
            }
            else if ( !m_xMap.GetNextTileCanMove(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, bDir, 1, ptTargetTile) )
            {
                ubyte bSelectedDirList[8] = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
                int nSeclectedDirCnt = -1;
                int nLastDistance = 100;
                int nCurrDistance;
                ubyte bInvDir;
                ubyte bSelectedDir = 255;
                
                if ( bLastDir < 4 ) bInvDir = cast(ubyte)(bLastDir + 4);
                else bInvDir = cast(ubyte)(bLastDir - 4);
                
                for ( int nCnt = 0; nCnt < _MAX_DIRECTION; nCnt++ )
                {
                    if ( m_xMap.GetNextTileCanMove(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, nCnt, 1, ptTargetTile) )
                    {
                        nCurrDistance = cast(int)(sqrt(cast(double)(ptTargetTile.getX()-m_pxSavedTargetActor.m_wPosX)*(ptTargetTile.getX()-m_pxSavedTargetActor.m_wPosX) + (ptTargetTile.getY()-m_pxSavedTargetActor.m_wPosY)*(ptTargetTile.getY()-m_pxSavedTargetActor.m_wPosY)));
                        if ( nCurrDistance <= nLastDistance && bInvDir != nCnt )
                        {
                            nLastDistance = nCurrDistance;
                            nSeclectedDirCnt++;
                            bSelectedDirList[nSeclectedDirCnt] = cast(ubyte)nCnt;
                        }
                    }
                }
                
                static ubyte bDirOrderList[8][8] = 
                [
                    [0, 7, 1, 6, 2, 5, 3, 4],
                    [1, 0, 2, 7, 3, 6, 4, 5],
                    [2, 1, 3, 0, 4, 7, 5, 6],
                    [3, 2, 4, 1, 5, 0, 6, 7],
                    [4, 5, 3, 6, 2, 7, 1, 0],
                    [5, 6, 4, 7, 3, 0, 2, 1],
                    [6, 7, 5, 0, 4, 1, 3, 2],
                    [7, 0, 6, 1, 5, 2, 4, 3]
                ];
                
                ubyte bOrderCnt = 0;
                
                for ( int nCnt = 0; nCnt < nSeclectedDirCnt; nCnt++ )
                {
                    while ( bSelectedDirList[nCnt] != bDirOrderList[bDir][bOrderCnt] || bOrderCnt < 8 ) bOrderCnt++;
                    if ( bOrderCnt >= 8 ) bOrderCnt = 0;
                    else                    
                    {   bSelectedDir = bLastDir = bSelectedDirList[nCnt];   break;  }
                }
                
                if ( bSelectedDir == 255 )
                    bSelectedDir = bLastDir = bSelectedDirList[randomRange(0, nSeclectedDirCnt+1)];

                if ( nSeclectedDirCnt != -1 )
                {
                    // 1Å¸ÀÏ ÀÌµ¿ÇÑ´Ù.
                    m_xMap.GetNextTileCanMove(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, bSelectedDir, 1, ptTargetTile);
                    if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE )
                    {
                        m_xMyHero.SetMotionState(Motion.Walk, bSelectedDir);
                    }
                    else
                    {
                        m_xMyHero.SetMotionState(Motion.HorseWalk, bSelectedDir);
                    }
                }
                else
                {
                    if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE )
                    {
                        m_xMyHero.SetMotionState(Motion.Stand, bDir);
                    }
                    else
                    {
                        m_xMyHero.SetMotionState(Motion.HorseStand, bDir);
                    }
                }
            }
            else
            {
                if ( m_xMyHero.m_stFeatureEx.Horse == _HORSE_NONE )
                {
                    m_xMyHero.SetMotionState(Motion.Stand, bDir);
                }
                else
                {
                    m_xMyHero.SetMotionState(Motion.HorseStand, bDir);
                }
            }
        }
    }
    
    //BOOL    ReceivePacket(CHAR* szMsg, INT nPacketLen);
    public void RenderObject(int nLoopTime)
    {
        const tint_color = al_map_rgba(255, 255, 255, 1);
        const tint_color2 = al_map_rgba(255, 255, 255, 0);
        //const tint_color = al_map_rgba(255, 0, 0, 0);
        //const tint_color2 = al_map_rgba(0, 255, 0, 0);


        int CalculateAnimationFrame(int objectAnimation, ref bool blend)
        {
            // ¾Ö´Ï¸ÞÀÌ¼Ç ¿ÀºêÁ§Æ®ÀÌ¸é.
            if ( objectAnimation != 255 )
            {
                ubyte bTickType = (objectAnimation & 0X70) >> 4;
                short shAniCnt = objectAnimation & 0X0F;
                
                if ( (objectAnimation & 0X80) >> 7 )
                    blend = true;

                return m_xMap.m_bAniTileFrame[bTickType][shAniCnt];
            }

            return 0;
        }

        ALLEGRO_BITMAP* bmp;
        ImageInfo imgi;

        PMapCellInfo cell;
        PMapTileInfo tile;
        int nXCnt, nYCnt, nStartX, nStartY, nObjFileIdx, nImgIdx, nAniImgIdx, nObjCnt;
        int dx, dy;
        bool bFocused = false;
        bool bLongObj = false;
        bool bBlend = false;
        bool bDrawShadow = true;

        Magic pxMagic;
        RepeatMagic pxRepeatMagic;
        MagicStream pxMagicStream;

        int op, source, dest;
        //al_get_blender(&op, &source, &dest);
        
        m_xMap.SetAniTileFrame(nLoopTime);
        
        // 48*32 Å¸ÀÏÇü ¿ÀºêÁ§Æ® ±×¸®±â.
        for ( nYCnt = m_xMap.m_shStartViewTileY-4; nYCnt < m_xMap.m_shStartViewTileY+_VIEW_CELL_Y_COUNT+6; nYCnt++ )
        {
            for ( nXCnt = m_xMap.m_shStartViewTileX-4; nXCnt < m_xMap.m_shStartViewTileX+_VIEW_CELL_X_COUNT+6; nXCnt++ )
            {
                if ( nYCnt >= m_xMap.Header.Height )
                    break;
                
                if ( nXCnt >= m_xMap.Header.Width || nXCnt < 0 || nYCnt < 0 )
                    continue;

                //if (!m_xMap.GetMapTile(nXCnt, nYCnt, tile)) continue;
                //if (!m_xMap.GetMapCell(nXCnt, nYCnt, cell)) continue;
                cell = &m_xMap.CellInfoArr[nYCnt + nXCnt*m_xMap.Header.Height];
                
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Test : ±¤¿øÀ» À§ÇØ¼­ -4ºÎÅÍ +5±îÁöÀÇ ¿µ¿ªÀ» ´õ Àâ´Â´Ù.
                LightInfo light = m_xMap.GetTileLightInfo(nXCnt, nYCnt);
                /*if ( light.IsLight )
                {
                    m_xLightFog.SetLightRadiusWithCircle((nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH-m_xMap.m_shViewOffsetX+_VIEW_CELL_X_START,
                                                         (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT-m_xMap.m_shViewOffsetY+_VIEW_CELL_Y_START, 
                                                         12, m_fTileLightBlue, m_fTileLightGreen, m_fTileLightRed);
                }*/
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                
                // ¿ÀºêÁ§Æ®°¡ ÀÖÀ»¶§.
                if ( cell.bFileIdx2 != 255 )
                {
                    // ¿ÀºêÁ§Æ®1ÀÌ ÀÖÀ»¶§.
                    if ( cell.wObj1 != 65535 )
                    {
                        nObjFileIdx = cell.bFileIdx2;
                        nImgIdx = cell.wObj1;
                        nImgIdx--;

                        //std.stdio.writeln("cell.bFlag1 ", cell.bFlag);
                        //std.stdio.writeln("nObjFileIdx ", nObjFileIdx, " nObjFileIdxex ", cell.bFileIdx2 & 0X0F);

                        if (( nObjFileIdx > 2 && nObjFileIdx < 14 ) || nObjFileIdx == _IMAGE_WOOD_SMOBJECTS )
                        {
                            bBlend = false;
                            
                            //nImgIdx += m_xMap.GetDoorImgIdx(nXCnt, nYCnt);

                            nImgIdx += CalculateAnimationFrame(cell.bObj1Ani, bBlend);

                            bmp = m_xMap.m_pxTileImg[nObjFileIdx].GetCachedImageEx(nImgIdx, imgi);
                            if ( bmp !is null )
                            {
                                if ( imgi.Width == 48 && imgi.Height == 32 )
                                {
                                    dx = (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX;
                                    dy = (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-imgi.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY;
                                    if ( !bBlend )
                                        al_draw_bitmap(bmp, dx, dy, 0);
                                    else
                                    {
                                        al_draw_tinted_bitmap(bmp, tint_color, dx, dy, 0);
                                    }
                                }
                            }
                        }
                    }
                }

                if ( cell.bFileIdx != 255 )
                {
                    // ¿ÀºêÁ§Æ®2°¡ ÀÖÀ»¶§.
                    if ( cell.wObj2 != 65535 )
                    {
                        nObjFileIdx = cell.bFileIdx;
                        nImgIdx = cell.wObj2;
                        nImgIdx--;
                        //std.stdio.writeln("cell.bFileIdx ", cell.bFileIdx, " cell.bFileIdx2 ", cell.bFileIdx2);
                        //std.stdio.writeln("cell.wObj2 ", cell.wObj2);
                        //std.stdio.writeln("nObjFileIdx ", nObjFileIdx, " cell.wObj2  ", cell.wObj2);

                        if (( nObjFileIdx > 2 && nObjFileIdx < 14 ) || nObjFileIdx == _IMAGE_WOOD_SMOBJECTS )
                        {
                            bBlend = false;
                            
                            //nImgIdx += m_xMap.GetDoorImgIdx(nXCnt, nYCnt);

                            nImgIdx += CalculateAnimationFrame(cell.bObj2Ani, bBlend);

                            bmp = m_xMap.m_pxTileImg[nObjFileIdx].GetCachedImageEx(nImgIdx, imgi);
                            if ( bmp !is null )
                            {
                                if ( imgi.Width == 48 && imgi.Height == 32 )
                                {
                                    dx = (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX;
                                    dy = (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-imgi.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY;
                                    if ( !bBlend )
                                        al_draw_bitmap(bmp, dx, dy, 0);
                                    else
                                    {
                                        al_draw_tinted_bitmap(bmp, tint_color, dx, dy, 0);
                                    }
                                }
                            }
                        }
                    }
                }

            }
        }   
        
        // 48*32°¡ ¾Æ´Ñ ±æÀÌ°¡ ÀÖ´Â Å¸ÀÏÇü ¿ÀºêÁ§Æ® ±×¸®±â.
        for ( nYCnt = m_xMap.m_shStartViewTileY; nYCnt < m_xMap.m_shStartViewTileY+_VIEW_CELL_Y_COUNT_FOR_OBJ; nYCnt++ )
        {
            for ( nXCnt = m_xMap.m_shStartViewTileX; nXCnt < m_xMap.m_shStartViewTileX+_VIEW_CELL_X_COUNT; nXCnt++ )
            {
                if ( nYCnt >= m_xMap.Header.Height )
                    break;
                if ( nXCnt >= m_xMap.Header.Width || nXCnt < 0 || nYCnt < 0 )
                    continue; 
                
                bLongObj = false;

                //if (!m_xMap.GetMapTile(nXCnt, nYCnt, tile)) continue;
                //if (!m_xMap.GetMapCell(nXCnt, nYCnt, cell)) continue;
                cell = &m_xMap.CellInfoArr[nYCnt + nXCnt*m_xMap.Header.Height];

                // ¿ÀºêÁ§Æ®°¡ ÀÖÀ»¶§.
                if ( cell.bFileIdx2 != 255 )
                {
                    // ¿ÀºêÁ§Æ®1ÀÌ ÀÖÀ»¶§.
                    if ( cell.wObj1 != 65535 )
                    {
                        nObjFileIdx = cell.bFileIdx2;
                        nImgIdx = cell.wObj1;
                        nImgIdx--;
                        
                        //if (nObjFileIdx >= 14)
                        //    std.stdio.writeln("nObjFileIdx ", nObjFileIdx, "cell.wObj1 ", cell.wObj1);
                        
                        if ( nObjFileIdx >= 2 && nObjFileIdx < 14 )
                        {
                            bBlend = false;
                            
                            //nImgIdx += m_xMap.GetDoorImgIdx(nXCnt, nYCnt);
                            
                            nImgIdx += CalculateAnimationFrame(cell.bObj1Ani, bBlend);
                            //bBlend = cell.bFlag > 0;
                            bmp = m_xMap.m_pxTileImg[nObjFileIdx].GetCachedImageEx(nImgIdx, imgi);
                            if ( bmp !is null )
                            {
                                if ( !(imgi.Width == 48 && imgi.Height == 32) )
                                {
                                    dx = (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX;
                                    dy = (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-imgi.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY;
                                    if ( !bBlend )
                                        al_draw_bitmap(bmp, dx, dy, 0);
                                    else
                                    {
                                        //al_set_blender(ALLEGRO_BLEND_OPERATIONS.ALLEGRO_ADD, ALLEGRO_BLEND_MODE.ALLEGRO_ONE, ALLEGRO_BLEND_MODE.ALLEGRO_INVERSE_ALPHA);
                                        al_draw_tinted_bitmap(bmp, tint_color2, dx, dy, 0);
                                        //al_set_blender(op, source, dest);
                                    }
                                    
                                    bLongObj = true;
                                }
                            }
                        }
                    }
                }

                if ( cell.bFileIdx != 255 )
                {
                    // ¿ÀºêÁ§Æ®2°¡ ÀÖÀ»¶§.
                    if ( cell.wObj2 != 65535 )
                    {
                        nObjFileIdx = cell.bFileIdx;
                        nImgIdx = cell.wObj2;
                        nImgIdx--;
                        
                        //std.stdio.writeln("cell.bFlag2 ", cell.bFlag);
                        
                        if ( nObjFileIdx >= 2 && nObjFileIdx < 14 )
                        {
                            bBlend = false;
                            
                            nImgIdx += m_xMap.GetDoorImgIdx(nXCnt, nYCnt);
                            
                            nImgIdx += CalculateAnimationFrame(cell.bObj2Ani, bBlend);
                            
                            //bBlend = cell.bFlag == 0;
                            bmp = m_xMap.m_pxTileImg[nObjFileIdx].GetCachedImageEx(nImgIdx, imgi);
                            if ( bmp !is null )
                            {
                                if ( !(imgi.Width == 48 && imgi.Height == 32) )
                                {
                                    dx = (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX;
                                    dy = (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-imgi.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY;
                                    if ( !bBlend )
                                        al_draw_bitmap(bmp, dx, dy, 0);
                                    else
                                    {
                                        al_draw_tinted_bitmap(bmp, tint_color, dx, dy, 0);
                                    }
                                    
                                    bLongObj = true;
                                }
                            }
                        }
                    }
                }
                
                //m_xMap.DrawOpenDoor(nXCnt, nYCnt);
                
                int nMapViewX = 0;
                int nMapViewY = 0;
                bool bIsMapViewTime = false;
                if ( nXCnt >= m_xMap.m_shStartViewTileX && nXCnt < m_xMap.m_shStartViewTileX + _VIEW_CELL_X_COUNT && 
                    nYCnt >= m_xMap.m_shStartViewTileY && nYCnt < m_xMap.m_shStartViewTileY + _VIEW_CELL_Y_COUNT )
                {
                    bIsMapViewTime = true;
                    nMapViewX = nXCnt - m_xMap.m_shStartViewTileX;
                    nMapViewY = nYCnt - m_xMap.m_shStartViewTileY;
                }
                
                // ¹Ù´Ú¾ÆÀÌÅÛ ±×¸®±â.
                if ( bIsMapViewTime )
                {
                    for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                    {
                        auto gitem = m_stMemMappedID[nMapViewY][nMapViewX].pstItem[nObjCnt];
                        if (gitem !is null)
                        {
                            ImageArray iarray = m_xImage[_IMAGE_ITEM_GROUND];
                            bmp = iarray[gitem.Looks];
                            if (bmp !is null)
                            {
                                m_xMap.GetScrnPosFromTilePos(gitem.TileX, gitem.TileY, nStartX, nStartY);
                                //nStartX = (pstItem.shTileX-m_xMap.m_shStartViewTileX)*_CELL_WIDTH+_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX;
                                //nStartY = (pstItem.shTileY-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY;
                                int nX = nStartX+_CELL_WIDTH/2-al_get_bitmap_width(bmp)/2;
                                int nY = nStartY+_CELL_HEIGHT/2-al_get_bitmap_height(bmp)/2;

                                const float bright = 0.3f;
                                const auto item_bright_color = al_map_rgba_f(1.0*bright, 1.0*bright, 1.0*bright, 1.0);
                                // TODO: draw item shadow..
                                /*g_xMainWnd.DrawWithShadowABlend(
                                    nX+1, nY+1, 
                                    pxItemImg.m_lpstNewCurrWilImageInfo.shWidth,
                                    pxItemImg.m_lpstNewCurrWilImageInfo.shHeight,
                                    (WORD*)pxItemImg.m_pbCurrImage, 
                                    _CLIP_WIDTH, _CLIP_HEIGHT, m_wShadowClr, false, 50);
                                */

                                if ( nXCnt == m_ptCurrTile.getX() && nYCnt == m_ptCurrTile.getY() )
                                    al_draw_tinted_bitmap(bmp, item_bright_color, nX, nY, 0);
                                else
                                    al_draw_bitmap(bmp, nX, nY, 0);
                            }
                        }
                        else
                            break;
                     }
                }
                
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // ³»Ä³¸¯ÅÍ ±×¸®±â.
                if ( nXCnt == m_xMyHero.m_wPosX && nYCnt == m_xMyHero.m_wPosY )
                {
                    // ±×¸²ÀÇ ½ÃÀÛÁÂÇ¥, Æ÷Ä¿½º»óÅÂ, ±×¸²ÀÚ ºí·»µù »óÅÂ¸¦ ³Ñ°ÜÁØ´Ù.
                    if ( m_xMyHero.m_rcActor.pointInside(m_ptMousePos) && m_pxMouseTargetActor is null )
                    {
                        bFocused = true;
                        m_pxMouseTargetActor = m_xMyHero;
                    }
                    else
                        bFocused = false;
                    
                    bDrawShadow = true;
                    if ( m_bShadowABlend )
                        bDrawShadow = false;

                    m_xMyHero.DrawActor(bFocused, m_bShadowABlend, false, bDrawShadow);
                }
                
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // ´Ù¸¥ Ä³¸¯ÅÍ ±×¸®±â.
                if ( bIsMapViewTime )
                {
                    for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                    {
                        Actor pxActor = m_stMemMappedID[nMapViewY][nMapViewX].pxActor[nObjCnt];
                        
                        if ( pxActor )
                        {
                            ubyte bOpa = 50;
                            
                            if ( pxActor.m_bIsDead )
                                bOpa = 30;
                            
                            if ( pxActor == m_pxMouseTargetActor )
                                bFocused = true;
                            else
                                bFocused = false;
                            
                            bDrawShadow = true;
                            if ( pxActor == m_pxMouseTargetActor && m_bShadowABlend )
                                bDrawShadow = false;
                            
                            switch ( pxActor.m_stFeature.Gender )
                            {
                                case _GENDER_MAN:
                                case _GENDER_WOMAN:
                                {
                                    Hero pxHero;
                                    pxHero = cast(Hero)pxActor;
                                    
                                    pxHero.DrawActor(m_xMap, bFocused, m_bShadowABlend, true, bDrawShadow);
                                    break;
                                }

                                case _GENDER_NPC:
                                {
                                    NPC pxNPC;
                                    pxNPC = cast(NPC)pxActor;
                                    
                                    pxNPC.DrawActor(m_xMap, bFocused, m_bShadowABlend, true, bDrawShadow);
                                    break;
                                }

                                case _GENDER_MON:
                                {
                                    pxActor.DrawActor(m_xMap, bFocused, m_bShadowABlend, true, bDrawShadow);
                                    
                                    /*                              // ¸»ÀÏ¶§.
                                    RECT rc, rcIntersect;
    //                              if ( bLongObj && pxActor.m_wPosY <= nYCnt && pxActor.m_stFeature.bDress > 114 && pxActor.m_stFeature.bDress < 118 )
                                    {
                                        SetRect(&rc, 
                                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX, 
                                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shHeight+_CELL_HEIGHT-m_xMap.m_shViewOffsetY, 
                                        m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shWidth  + (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX, 
                                        m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shHeight + (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shHeight+_CELL_HEIGHT-m_xMap.m_shViewOffsetY);

                                        // ¸»°ú¹è°æ.
                                        if ( IntersectRect(&rcIntersect, &rc, &pxActor.m_rcActor) )
                                        {
                                            m_xImage.m_xImageList[pxActor.m_bActorImgIdx].NewSetIndex(pxActor.m_dwCurrFrame);
                                            g_xMainWnd.DrawWithABlendForIntersectCompData(
                                                            pxActor.m_rcActor.left, 
                                                            pxActor.m_rcActor.top,
                                                            m_xImage.m_xImageList[pxActor.m_bActorImgIdx].m_lpstNewCurrWilImageInfo.shWidth,
                                                            m_xImage.m_xImageList[pxActor.m_bActorImgIdx].m_lpstNewCurrWilImageInfo.shHeight,
                                                            (WORD*)m_xImage.m_xImageList[pxActor.m_bActorImgIdx].m_pbCurrImage,
                                                            rc.left,
                                                            rc.top,
                                                            m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shWidth,
                                                            m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shHeight,
                                                            (WORD*)m_xMap.m_pxTileImg[nObjFileIdx].m_pbCurrImage,
                                                            _CLIP_WIDTH, _CLIP_HEIGHT, 50, bFocused, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, m_xMyHero.m_wStateClr);
                                        }
                                    }*/
                                    break;
                                }

                                default: break;
                            }
                            
                            bFocused = false;
                        }
                        else
                            break;
                    }
                }
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                if ( bIsMapViewTime )
                {
                    for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                    {
                        pxMagic = m_stMemMappedID[nMapViewY][nMapViewX].pxMagic[nObjCnt];
                        if ( pxMagic !is null )
                        {
                            if ( pxMagic.m_bMagicNum == _SKILL_HOLYSHIELD || pxMagic.m_bMagicNum == _SKILL_EARTHFIRE )
                            {
                                pxRepeatMagic = cast(RepeatMagic)pxMagic;
                                
                                pxRepeatMagic.DrawMagic();
                            }
                            else if ( pxMagic.m_bMagicNum == _SKILL_FIRE )
                            {
                                pxMagicStream = cast(MagicStream)pxMagic;
                                
                                pxMagicStream.DrawMagic();
                            }
                        }
                        else
                            break;
                    }
                }
            }
        }

        //al_set_blender(op, source, dest);

        bDrawShadow = false;
        if ( m_bShadowABlend )
            bDrawShadow = true;
        
        m_xMyHero.m_wABlendDelay = 10;
        m_xMyHero.m_wABlendCurrDelay = 5;
        
        m_xMyHero.DrawActor(false, m_bShadowABlend, false, bDrawShadow);
        
        m_xMyHero.m_wABlendDelay = 0;
        m_xMyHero.m_wABlendCurrDelay = 0;
        
        if ( m_pxMouseTargetActor !is null && m_pxMouseTargetActor !is m_xMyHero /*&& !m_pxMouseTargetActor.m_bIsDead*/ )
        {
            m_pxMouseTargetActor.m_wABlendDelay = 10;
            m_pxMouseTargetActor.m_wABlendCurrDelay = 4;
            
            m_pxMouseTargetActor.DrawActor(m_xMap, false, m_bShadowABlend, false, bDrawShadow);
            
            m_pxMouseTargetActor.m_wABlendDelay = 0;
            m_pxMouseTargetActor.m_wABlendCurrDelay = 0;
        }
    }
    
    //BOOL    CheckMove(INT nX, INT nY, INT nSpeed, POINT* ptDestTile = NULL, INT* nDestDir = NULL);
    public void CheckMappedData(int nLoopTime, bool bIsMoveTime)
    {
        int nCnt, nObjCnt, nMapViewX, nMapViewY;
        bool bIsSaveTargetExisted = false;
        bool bFocused;

        
        m_stMemMappedID = m_stMemMappedID.init;

        Actor pxActor = null;
        Actor pxDeadTargetActor = null;

        nCnt = 0;
        while (true)
        {
            if (nCnt >= ActorList.count()) break;
            pxActor = ActorList[nCnt];

            if ( pxActor is null )
                continue;
            
            switch ( pxActor.m_stFeature.Gender )
            {
                case _GENDER_MAN:
                case _GENDER_WOMAN:
                {
                    Hero pxHero = cast(Hero)pxActor;
                    pxHero.UpdateMotionState(nLoopTime, bIsMoveTime);
                    nCnt++;
                    break;
                }

                case _GENDER_NPC:
                {
                    NPC pxNPC = cast(NPC)pxActor;
                    pxNPC.UpdateMotionState(nLoopTime, bIsMoveTime);
                    nCnt++;
                    break;
                }

                case _GENDER_MON:
                {
                    pxActor.UpdateMotionState(nLoopTime, bIsMoveTime);
                    
                    if ( pxActor.m_bAppearState == _DIG_DOWNDEL )
                    {
                        ActorList.deleteAt(nCnt);
                        clear(pxActor);
                        pxActor = null;
                    }
                    else
                    {
                        nCnt++;
                    }
                    break;
                }
                default: break;
            }
            
            if ( pxActor is null )
                continue;

            if ( pxActor.m_wPosX >= m_xMap.m_shStartViewTileX && pxActor.m_wPosX < m_xMap.m_shStartViewTileX + _VIEW_CELL_X_COUNT && 
                pxActor.m_wPosY >= m_xMap.m_shStartViewTileY && pxActor.m_wPosY < m_xMap.m_shStartViewTileY + _VIEW_CELL_Y_COUNT )                
            {
                nMapViewX = pxActor.m_wPosX - m_xMap.m_shStartViewTileX;
                nMapViewY = pxActor.m_wPosY - m_xMap.m_shStartViewTileY;

                for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                {
                    if ( m_stMemMappedID[nMapViewY][nMapViewX].pxActor[nObjCnt] is null )
                    {
                        bFocused = false;
                        if ( pxActor is m_pxSavedTargetActor )
                        {
                            bIsSaveTargetExisted = true;
                        }
                        
                        // ±×¸²ÀÇ ½ÃÀÛÁÂÇ¥, Æ÷Ä¿½º»óÅÂ, ±×¸²ÀÚ ºí·»µù »óÅÂ¸¦ ³Ñ°ÜÁØ´Ù.
                        if ( m_pxMouseTargetActor is null /*&& !pxActor.m_bIsDead*/ )
                        {
                            if ( pxActor.m_rcActor.pointInside(m_ptMousePos) )
                            {
                                m_pxMouseTargetActor = pxActor;
                                bFocused = true;
                            }
                        }
                        else
                        {
                            if ( pxActor.m_rcTargetRgn.pointInside(m_ptMousePos) )
                            {
                                if ( !pxActor.m_bIsDead )
                                {
                                    m_pxMouseTargetActor = pxActor;
                                    bFocused = true;
                                }
                                else
                                {
                                    pxDeadTargetActor = pxActor;
                                    bFocused = true;
                                }
                            }
                        }   
                        
                        // Á×Àº Actor´Â ¾ÕÀ¸·Î ¶¯±ä´Ù.
                        if ( pxActor.m_bIsDead )
                        {
                            // TODO:
                            /*CActor* pxTempActor[_MAX_CELL_OBJ];
                            ZeroMemory(pxTempActor, sizeof(CActor*)*_MAX_CELL_OBJ);
                            
                            pxTempActor[0] = pxActor;
                            memcpy(&pxTempActor[1], m_stMemMappedID[nObjY][nObjX].pxActor, sizeof(CActor*)*(_MAX_CELL_OBJ-1));
                            memcpy(m_stMemMappedID[nObjY][nObjX].pxActor, pxTempActor, sizeof(CActor*)*(_MAX_CELL_OBJ));
                            */
/*                      switch ( pxActor.m_stFeature.bGender )
                        {
                        case _GENDER_MAN:
                        case _GENDER_WOMAN:
                            {
                                CHero* pxHero;
                                pxHero = (CHero*)pxActor;
                                pxHero.DrawActor(&m_xMap, bFocused);
                            }
                            break;
                        case _GENDER_NPC:
                            {
                                CNPC* pxNPC;
                                pxNPC = (CNPC*)pxActor;
                                pxNPC.DrawActor(&m_xMap, bFocused);
                            }
                            break;
                        case _GENDER_MON:
                            {
                                pxActor.DrawActor(&m_xMap, bFocused);
                            }
                            break;
                        }
*/
                        }
                        else
                            m_stMemMappedID[nMapViewY][nMapViewX].pxActor[nObjCnt] = pxActor;
                        
                        break;
                    }
                }
            }
        } 
        
        if ( !bIsSaveTargetExisted ) m_pxSavedTargetActor = null;
        
        if ( m_pxMouseTargetActor is null && pxDeadTargetActor !is null )
        {
            m_pxMouseTargetActor = pxDeadTargetActor;
        }

        Magic pxMagic;
        nCnt = 0;
        while (true)
        {
            if (nCnt >= GroundMagicList.count()) break;
            pxMagic = GroundMagicList[nCnt];

            nMapViewX = pxMagic.m_shTargetTileX - m_xMap.m_shStartViewTileX;
            nMapViewY = pxMagic.m_shTargetTileY - m_xMap.m_shStartViewTileY;
            
            if ( pxMagic.m_bMagicNum == _SKILL_HOLYSHIELD || pxMagic.m_bMagicNum == _SKILL_EARTHFIRE )
            {
                RepeatMagic pxRepeatMagic = cast(RepeatMagic)pxMagic;
                
                pxRepeatMagic.UpdateMagic(nLoopTime);
                
                if ( pxRepeatMagic.m_bActiveState == _MAGIC_FINISH )
                {
                    GroundMagicList.deleteAt(nCnt);
                    clear(pxRepeatMagic);
                    pxRepeatMagic = null;
                }
                else
                {
                    if ( pxMagic.m_shTargetTileX >= m_xMap.m_shStartViewTileX && pxMagic.m_shTargetTileX < m_xMap.m_shStartViewTileX  + _VIEW_CELL_X_COUNT && 
                        pxMagic.m_shTargetTileY >= m_xMap.m_shStartViewTileY && pxMagic.m_shTargetTileY < m_xMap.m_shStartViewTileY  + _VIEW_CELL_Y_COUNT )
                    {
                        for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                        {
                            if ( m_stMemMappedID[nMapViewY][nMapViewX].pxMagic[nObjCnt] is null )
                            {
                                m_stMemMappedID[nMapViewY][nMapViewX].pxMagic[nObjCnt] = pxMagic;
                                break;
                            }
                        }
                    }

                    nCnt++;
                }
            }
            else if ( pxMagic.m_bMagicNum == _SKILL_FIRE )
            {
                MagicStream pxMagicStream = cast(MagicStream)pxMagic;
                
                pxMagicStream.UpdateMagic(nLoopTime);
                
                if ( pxMagicStream.m_bActiveState == _MAGIC_FINISH )
                {
                    GroundMagicList.deleteAt(nCnt);
                    clear(pxMagicStream);
                    pxMagicStream = null;
                }
                else
                {
                    if ( pxMagic.m_shTargetTileX >= m_xMap.m_shStartViewTileX && pxMagic.m_shTargetTileX < m_xMap.m_shStartViewTileX  + _VIEW_CELL_X_COUNT && 
                        pxMagic.m_shTargetTileY >= m_xMap.m_shStartViewTileY && pxMagic.m_shTargetTileY < m_xMap.m_shStartViewTileY  + _VIEW_CELL_Y_COUNT )
                    {
                        for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                        {
                            if ( m_stMemMappedID[nMapViewY][nMapViewX].pxMagic[nObjCnt] is null )
                            {
                                m_stMemMappedID[nMapViewY][nMapViewX].pxMagic[nObjCnt] = pxMagic;
                                break;
                            }
                        }
                    }

                    nCnt++;
                }
            }
         }

        for ( nCnt = 0; nCnt < MapItemList.count(); nCnt++ )
        {
            PGroundItem gitem = MapItemList[nCnt];
            
            if ( gitem.TileX >= m_xMap.m_shStartViewTileX && gitem.TileX < m_xMap.m_shStartViewTileX  + _VIEW_CELL_X_COUNT && 
                gitem.TileY >= m_xMap.m_shStartViewTileY && gitem.TileY < m_xMap.m_shStartViewTileY  + _VIEW_CELL_Y_COUNT )
            {
                nMapViewX = gitem.TileX - m_xMap.m_shStartViewTileX;
                nMapViewY = gitem.TileY - m_xMap.m_shStartViewTileY;
                
                for ( nObjCnt = 0; nObjCnt < _MAX_CELL_OBJ; nObjCnt++ )
                {
                    if ( m_stMemMappedID[nMapViewY][nMapViewX].pstItem[nObjCnt] is null )
                    {
                        m_stMemMappedID[nMapViewY][nMapViewX].pstItem[nObjCnt] = gitem;
                        break;
                    }
                }
            }
        }
    }
    
    public void RenderMapTileGrid()
    {
        const auto alpha = 125/255.0f;
        const auto cell_color = al_map_rgba_f(0.0, 1.0, 1.0, 1.0);
        const auto tile_color = al_map_rgba_f(1.0, 0.0, 0.0, 1.0);
        const auto stop_color = al_map_rgba_f(1.0*alpha, 1.0*alpha, 0.0, alpha);

        ushort bCanMove = false;
        int nObjCnt1 = 0, nObjCnt2 = 0;

        PMapCellInfo cell;
        PMapTileInfo tile;
        int nObjFileIdx, nFileIdx, nImgIdx;
        int dx, dy;

        ALLEGRO_BITMAP* bmp;
        ImageInfo imgi;

        //IntRectangle rc;
        
        if ( m_bCellView || m_bTileView || m_bObj1View || m_bObj2View || m_bStopPtView )
        {
            for ( int nXCnt = m_xMap.m_shStartViewTileX; nXCnt < m_xMap.m_shStartViewTileX+_VIEW_CELL_X_COUNT; nXCnt++ )
                for ( int nYCnt = m_xMap.m_shStartViewTileY; nYCnt < m_xMap.m_shStartViewTileY+_VIEW_CELL_Y_COUNT_FOR_OBJ; nYCnt++ )
            {
                //if ( nXCnt >= m_xMap.Header.Width || nYCnt >= m_xMap.Header.Height || nXCnt < 0 || nYCnt < 0 )
                //    continue; 

                if (!m_xMap.GetMapTile(nXCnt, nYCnt, tile)) continue;
                if (!m_xMap.GetMapCell(nXCnt, nYCnt, cell)) continue;

                nFileIdx = tile.bFileIdx;
                nImgIdx = tile.wTileIdx;

                // Cell±×¸®µå º¸¿©ÁÖ±â.
                if ( m_bCellView )
                {
                    m_xMap.GetScrnPosFromTilePos(nXCnt, nYCnt, dx, dy);
                    al_draw_rectangle(dx, dy, dx+_CELL_WIDTH, dy+_CELL_HEIGHT, cell_color, 1.0f);
                }
                
                if ( m_bTileView )
                {
                    // Å¸ÀÏ±×¸®µåº¸¿©ÁÖ±â.
                    if( !( nXCnt % 2 ) && !( nYCnt % 2 ) && nYCnt < m_xMap.m_shStartViewTileY+_VIEW_CELL_Y_COUNT )
                    {
                        if( nFileIdx != 255 && nImgIdx != 65535 )
                        {
                            nImgIdx--;
                            bmp = m_xMap.m_pxTileImg[nFileIdx].GetCachedImageEx(nImgIdx, imgi);
                            m_xMap.GetScrnPosFromTilePos(nXCnt, nYCnt, dx, dy);
                            al_draw_rectangle(dx, dy, dx+imgi.Width, dy+imgi.Height, tile_color, 1.0f);
                            /+m_xMap.m_pxTileImg[nFileIdx].NewSetIndex(nImgIdx);
                            
                            SetRect(&rc,
                                    (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                                    (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY,
                                    (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START+m_xMap.m_pxTileImg[nFileIdx].m_lpstNewCurrWilImageInfo.shWidth -m_xMap.m_shViewOffsetX,
                                    (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START+m_xMap.m_pxTileImg[nFileIdx].m_lpstNewCurrWilImageInfo.Height-m_xMap.m_shViewOffsetY);
                            g_xMainWnd.DrawWithGDI(rc, NULL, RGB(255, 0, 0), 1);+/
                        }
                    }
                }
                
                if ( m_bObj1View )
                {
                    // Obj1Å¸ÀÏ ±×¸®µå º¸¿©ÁÖ±â.
                    if ( cell.bFileIdx2 != 255 )
                    {
                        if ( cell.wObj1 != 65535 )
                        {
                            nObjFileIdx = cell.bFileIdx2;
                            nImgIdx = cell.wObj1;
                            nImgIdx--;
                            
                            if ( nObjFileIdx > 2 && nObjFileIdx < 14 )
                            {
                                /+m_xMap.m_pxTileImg[nObjFileIdx].NewSetIndex(nImgIdx);
                                SetRect(&rc,
                                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY,
                                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START+m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shWidth -m_xMap.m_shViewOffsetX,
                                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START+m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.Height-m_xMap.m_shViewOffsetY);
                                
                                //                          if ( PtInRect(&rc, m_ptMousePos) )
                                {
                                    nObjCnt1++;
                                    g_xMainWnd.DrawWithGDI(rc, NULL, RGB(255, 0, 255), 1);
                                    
                                    TCHAR szBuff[MAX_PATH];
                                    sprintf(szBuff, "[%d]%d%d", nObjCnt1, nXCnt, nYCnt);
                                    g_xMainWnd.PutsHan(g_xMainWnd.GetBackBuffer(), 
                                                       (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                                                       (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY,
                                                       RGB(255, 0, 255), RGB(0, 0, 0), szBuff);
                                }+/
                            }
                        }
                    }
                }

   
                if ( m_bObj2View )
                {
                    // Obj2Å¸ÀÏ ±×¸®µå º¸¿©ÁÖ±â.
                    if ( cell.bFileIdx != 255 )
                    {
                        if ( cell.wObj2 != 65535 /*&& m_shObjTileViewState == 2*/ )
                        {
                            nObjFileIdx = cell.bFileIdx;
                            nImgIdx = cell.wObj2;
                            nImgIdx--;

                            if ( nObjFileIdx > 2 && nObjFileIdx < 14 )
                            {
                                /+m_xMap.m_pxTileImg[nObjFileIdx].NewSetIndex(nImgIdx);
                                SetRect(&rc,
                                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY,
                                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START+m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.shWidth -m_xMap.m_shViewOffsetX,
                                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START+_CELL_HEIGHT-m_xMap.m_shViewOffsetY);
                                
                                //                          if ( PtInRect(&rc, m_ptMousePos) )
                                {
                                    nObjCnt2++;
                                    g_xMainWnd.DrawWithGDI(rc, NULL, RGB(0, 255, 255), 1);
                                    
                                    TCHAR szBuff[MAX_PATH];
                                    sprintf(szBuff, "[%d]%d%d", nObjCnt2, nXCnt, nYCnt);
                                    g_xMainWnd.PutsHan(g_xMainWnd.GetBackBuffer(), 
                                                       (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                                                       (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_pxTileImg[nObjFileIdx].m_lpstNewCurrWilImageInfo.Height+_CELL_HEIGHT-m_xMap.m_shViewOffsetY,
                                                       RGB(0, 255, 255), RGB(0, 0, 0), szBuff);
                                }+/
                            }
                        }
                    }
                }
                
                if ( m_bStopPtView )
                {
                    bCanMove  = m_xMap.GetTileAttribute(nXCnt, nYCnt);
                    if ( bCanMove != _CAN_WALK && m_bStopPtView )
                    {
                        m_xMap.GetScrnPosFromTilePos(nXCnt, nYCnt, dx, dy);
                        al_draw_filled_rectangle(dx, dy, dx+_CELL_WIDTH, dy+_CELL_HEIGHT, stop_color);
                    }
                }
                
                /*          if ( ( m_xMap.CellInfoArr[nArrayNum].wLigntNEvent & 0X07 ) == 2 )
            {
                SetRect(&rc,
                       (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                       (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY,
                       (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START+_CELL_WIDTH -m_xMap.m_shViewOffsetX,
                       (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START+_CELL_HEIGHT-m_xMap.m_shViewOffsetY);
                g_xMainWnd.DrawWithGDI(rc, NULL, RGB(255, 255, 255), 2);
            }
*/
            }
        }

        for ( int nXCnt = m_xMap.m_shStartViewTileX; nXCnt < m_xMap.m_shStartViewTileX+_VIEW_CELL_X_COUNT; nXCnt++ )
            for ( int nYCnt = m_xMap.m_shStartViewTileY; nYCnt < m_xMap.m_shStartViewTileY+_VIEW_CELL_Y_COUNT_FOR_OBJ; nYCnt++ )
        {
            if ( nXCnt >= m_xMap.Header.Width || nYCnt >= m_xMap.Header.Height || nXCnt < 0 || nYCnt < 0 )
                continue; 
            
            //      if ( m_xMap.GetDoor(nXCnt, nYCnt) )
            if ( !m_xMap.IsDoorOpen(nXCnt, nYCnt) )
            {
                /+SetRect(&rc,
                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX,
                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY,
                        (nXCnt-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START+_CELL_WIDTH -m_xMap.m_shViewOffsetX,
                        (nYCnt-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START+_CELL_HEIGHT-m_xMap.m_shViewOffsetY);
                g_xMainWnd.DrawWithGDI(rc, NULL, RGB(255, 255, 255), 1);+/
            }
        }
    }

    //VOID    CommandAnalyze();
    
    public bool TargetInLongAttack(ubyte dir)
    {
        IntPoint ptTarget;
        if ( !m_xMap.GetNextTileCanMove(m_xMyHero.m_wPosX, m_xMyHero.m_wPosY, dir, 2, ptTarget) )
        {
            for (int i = 0; i < ActorList.count; i++)
            {
                Actor lactor = ActorList[i];
                if ( lactor.m_wPosX == ptTarget.getX() && lactor.m_wPosY == ptTarget.getY() )
                    return true;
            }
        }
        
        return false;
    }
    
    //VOID    ProcessPacket();
    //VOID    ProcessDefaultPacket();
    
    //VOID    CloseNPCWindow();
    
    public void showStatus(int nStartX, int nStartY)
    {
        string buffer;

        if ( m_bStatusView )
        {
            buffer = format("CurrentTile X:%s, Y:%s", m_ptCurrTile.getX(), m_ptCurrTile.getY());
            MyPen.drawText(nStartX, nStartY+10, al_map_rgba(250, 250, 250, 255), buffer);
            
            buffer = format("ServerIP: %s", g_szServerIP);
            MyPen.drawText(nStartX, nStartY+25, al_map_rgba(250, 250, 250, 255), buffer);
            
            buffer = format("Mouse X:%s, Y:%s", m_ptMousePos.getX(), m_ptMousePos.getY());
            MyPen.drawText(nStartX, nStartY+40, al_map_rgba(250, 250, 250, 255), buffer);
            
            buffer = format("MyIdentity:%x, %s", m_xMyHero.m_dwIdentity, m_xWaitPacketQueue.count());
            MyPen.drawText(nStartX, nStartY+55, al_map_rgba(250, 250, 250, 255), buffer);
            
            for (int i = 0; i < ActorList.count(); i++)
            {
                Actor lactor = ActorList[i];
                
                buffer = format("IDNUM:%x, X:%s, Y:%s, MSGCNT:%s", lactor.m_dwIdentity, lactor.m_wPosX, lactor.m_wPosY, lactor.m_xPacketQueue.count());
                MyPen.drawText(lactor.m_shScrnPosX, lactor.m_shScrnPosY, al_map_rgba(250, 250, 250, 255), buffer);
             }
            
            //g_xMainWnd.UsedAndFreeMemoryCheck();
            //sprintf(szBuff, "ÅØ½ºÃçÀüÃ¼:%d, ÅØ½ºÃç¿©À¯:%d, »ç¿ëÇÑÅØ½ºÃç:%d", g_xMainWnd.m_dwTextureTotal, g_xMainWnd.m_dwTextureFree, g_xMainWnd.m_dwTextureTotal-g_xMainWnd.m_dwTextureFree);
            //g_xMainWnd.PutsHan(g_xMainWnd.GetBackBuffer(), nStartX, nStartY+70, RGB(250, 250, 250), RGB(0, 0, 0), szBuff);
            
            //sprintf(szBuff, "ºñµð¿À·¥ÀüÃ¼:%d, ºñµð¿À·¥¿©À¯:%d, »ç¿ëÇÑºñµð¿À·¥:%d", g_xMainWnd.m_dwVideoTotal, g_xMainWnd.m_dwVideoFree, g_xMainWnd.m_dwVideoTotal-g_xMainWnd.m_dwVideoFree);
            //g_xMainWnd.PutsHan(g_xMainWnd.GetBackBuffer(), nStartX, nStartY+85, RGB(250, 250, 250), RGB(0, 0, 0), szBuff);
        }
        
        if ( m_bShowFPS )
        {
            buffer = format("FPS: %s", SceneMan.CurrentFPS);
            MyPen.drawText(750, 0, al_map_rgba(250, 250, 250, 255), buffer);
        }
    }

    public void UpdateShine(int nLoopTime)
    {
        auto curtime = Clock.currSystemTick();
        
        if ( (curtime - m_dwLastShineTick).msecs > 5000 )
        {
            m_bShowShine = true;
            m_dwLastShineTick = curtime;
            m_wShineCurrDelay = 0;
            m_bCurrShineFrame = 0;
        }
        
        m_wShineCurrDelay += nLoopTime;
        if ( m_wShineCurrDelay > 120 )
        {
            m_bCurrShineFrame++;
            m_wShineCurrDelay = 0;
            if ( m_bCurrShineFrame > 9 )
            {
                m_bCurrShineFrame = 0;
                m_bShowShine = false;
            }
        }
    }
    
    public bool RenderShine(int nLoopTime)
    {
        if ( m_bShowShine )
        {
            ImageArray iarray = m_xImage[_IMAGE_PROGUSE];
            ALLEGRO_BITMAP* bmp = iarray[m_bCurrShineFrame + 40];
            
            if (bmp !is null)
            {
                if (MapItemList.count() > 0)
                {
                    for (int i = 0; i < MapItemList.count(); i++)
                    {
                        PGroundItem gitem = MapItemList[i];

                        int nCenterX, nCenterY;
                        m_xMap.GetScrnPosFromTilePos(gitem.TileX, gitem.TileY, nCenterX, nCenterY);
                        // PDS: after testing
                        //int nCenterX = (gitem.TileX-m_xMap.m_shStartViewTileX)*_CELL_WIDTH +_VIEW_CELL_X_START-m_xMap.m_shViewOffsetX+_CELL_WIDTH /2;
                        //int nCenterY = (gitem.TileY-m_xMap.m_shStartViewTileY)*_CELL_HEIGHT+_VIEW_CELL_Y_START-m_xMap.m_shViewOffsetY+_CELL_HEIGHT/2;
                        
                        auto tint_color = al_map_rgba(255, 255, 255, 1);
                        
                        al_draw_tinted_scaled_rotated_bitmap(bmp,
                                                             tint_color, 0f, 0f, nCenterX, nCenterY, 1.0f, 1.0f,
                                                             0f, 0);
                    }
                }
            }
            
            return true;
        }

        return false;
    }


    public Actor findActor(int id)
    {
        for (int i = 0; i < ActorList.count; i++)
        {
            Actor lactor = ActorList[i];
            if (lactor.m_dwIdentity == id)
                return lactor;
        }
        return null;
    }

    public Actor findActorXY(int x, int y)
    {
        for (int i = 0; i < ActorList.count(); i++)
        {
            Actor lactor = ActorList[i];
            if ((lactor.m_wPosX == x) && (lactor.m_wPosY == y))
            {
                if (!lactor.m_bIsDead) //&& lactor.Visible && lactor.BoHoldPlace)
                    return lactor;
            }
        }
        return null;
    }
    
    public bool isValidActor(Actor actor)
    {
        for (int i = 0; i < ActorList.count(); i++)
        {
            Actor lactor = ActorList[i];
            if (lactor is actor)
                return true;
        }
        return false;
    }
    
    //function NewActor(chrid: integer; cx, cy, cdir: word; cfeature, cstate: integer): TActor;
    
    //Á×Àº actor´Â ¸Ç À§·Î
    public void actorDied(Actor actor)
    {
        Actor lactor;
        int i;
        
        for (i = 0; i < ActorList.count; i++)
        {
            lactor = ActorList[i];
            if (lactor is actor)
            {
                ActorList.deleteAt(i);
                break;
            }
        }

        bool flag = false;
        for (i = 0; i < ActorList.count; i++)
        {
            lactor = ActorList[i];
            /*if (!lactor.Death)
            {
                ActorList.insertAt(i, actor);
                flag = true;
                break;
            }*/
        }
        
        if (!flag) ActorList.add(actor);
    }
    
    public void setActorDrawLevel(Actor actor, int level)
    {
        if (level == 0) //¸Ç Ã³À½¿¡ ±×¸®µµ·Ï ÇÔ
        {
            for (int i = 0; i < ActorList.count; i++)
            {
                Actor lactor = ActorList[i];
                if (lactor is actor)
                {
                    ActorList.deleteAt(i);
                    ActorList.insertAt(0, actor);
                    break;
                }
            }
        }
    }
    
    //·Î±×¾Æ¿ô¸¸ »ç¿ë
    public void clearActors()
    {
        int i;
        
        for (i = 0; i < ActorList.count; i++)
        {
            Actor lactor = ActorList[i];
            destroy(lactor);
        }
        ActorList.clear();
        
        /*MyHero = null;
        MyHero.TargetCret = null;
        MyHero.FocusCret = null;
        MyHero.MagicTarget = null;

        //¸¶¹ýµµ ÃÊ±âÈ­ ÇØ¾ßÇÔ.
        for (i = 0; i < EffectList.count; i++)
        {
            MagicEff meff = EffectList[i];
            destroy(meff);
        }
        EffectList.clear();*/
    }
    
    public void deleteActor(int id)
    {
        int i = 0;
        while (true)
        {
            if (i >= ActorList.count) break;
            Actor lactor = ActorList[i];
            
            if (lactor.m_dwIdentity == id)
            {
                // TODO: uncomment..
                //if (TargetCret is lactor) TargetCret = null;
                //if (FocusCret is lactor) FocusCret = null;
                //if (MagicTarget is lactor) MagicTarget = null;
                //lactor.DeleteTime = Clock.currSystemTick();
                FreeActorList.add(lactor);
                ActorList.deleteAt(i);
            }
            else
                i++;
        }
    }
}